from handler.HandlerBase import HandlerBase
import requests
from string import Template
from collections import Sequence
import logging
import re


class Rest(HandlerBase):
	def __init__(self, content):
		self.parameters = content.get('parameters')
		if self.parameters is None:
			self.parameters = {}

		self.create_templates(content)

		self.handle_sequence(self.begin)

	def change_state(self, from_state, to_state):
		self.handle_sequence(self.before)

		if isinstance(to_state, dict):
			for key in to_state:
				self.parameters[key] = to_state[key]
		else:
			self.parameters['state'] = to_state

		self.handle_sequence(self.state)

	def close(self):
		self.handle_sequence(self.end)

	def create_templates(self, content):
		self.begin = self.get_templated(content.get('begin'))
		self.before = self.get_templated(content.get('before'))
		self.state = self.get_templated(content.get('state'))
		self.after = self.get_templated(content.get('after'))
		self.end = self.get_templated(content.get('end'))

	def get_templated(self, sequence):
		if sequence is None:
			return None

		for call in sequence:
			self.set_call_templates(call)

		return sequence

	def handle_sequence(self, sequence):
		if sequence is None:
			return

		for call in sequence:
			url = call['url'].substitute(self.parameters)
			verb = call['verb']

			headers_template = call['headers']
			headers = None
			if headers_template is not None:
				print(self.parameters)
				headers = headers_template.substitute(self.parameters)

			data_template = call.get('data')
			data = None
			if data_template is not None:
				data = data_template.substitute

			response_definition = call.get('response')

			if verb.lower() == 'get':
				response = requests.get(url, headers=headers)
			elif verb.lower() == 'post':
				response = requests.post(url, headers=headers, data=data)
			elif verb.lower() == 'put':
				response = requests.put(url, headers=headers, data=data)
			elif verb.lower() == 'patch':
				response = requests.patch(url, headers=headers, data=data)
			elif verb.lower() == 'delete':
				response = requests.delete(url, headers=headers, data=data)

			self.set_parameters_from_response_dict(response, response_definition)

	def set_parameters_from_response_dict(self, response, response_definition):
		if response is None or response_definition is None:
			return

		for key in response:
			value = response[key]

			definition = response_definition.get(key)
			if value is None or definition is None:
				return

			if isinstance(value, dict):
				self.set_parameters_from_response_dict(value, definition)
			elif isinstance(value, Sequence) and not isinstance(value, str):
				self.set_parameters_from_response_sequence(value, definition)

			self.set_parameter_by_value(value, definition)

	def set_parameters_from_response_sequence(self, responses, response_definition):
		if responses is None or response_definition is None or isinstance(response_definition, Sequence) is False:
			return

		if len(responses) != len(response_definition):
			logging.warning('responses was ' + str(responses) + ' could not match ' + str(response_definition))
			return

		for index, response in enumerate(responses):
			definition = response_definition[index]
			if response is None or definition is None:
				return

			if isinstance(response, dict):
				self.set_parameters_from_response_dict(response, definition)
			elif isinstance(response, Sequence) and not isinstance(response, str):
				self.set_parameters_from_response_seq(response, definition)

			self.set_parameter_by_value(response, definition)

	def set_parameter_by_value(self, value, definition):
		if isinstance(definition, str):
			if definition in self.parameters:
				self.parameters[definition] = value
				return

		name = definition['parameter']
		expression = definition['expression']

		matches = re.findall(expression, value)

		if len(matches) == 0:
			return

		if len(matches) == 1:
			self.parameters[name] = matches[0]
			return

		self.parameters[name] = matches

	def set_call_templates(self, call):
			url = call.get('url')
			if url is None:
				url = self.base_url
			call['url'] = Template(url)

			headers = call['headers']
			if headers is not None:
				call['headers'] = Template(headers)

			data = call.get('data')
			if data is not None:
				call['data'] = Template(data)
